package org.rcgwt.client.ui.calendar.model.impl;

import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

import org.rcgwt.client.ui.calendar.i18n.CalendarUtils;
import org.rcgwt.client.ui.calendar.model.ICalendarModel;

/**
 * The MVC component : the model
 * 
 * @author Elian ORIOU
 */

@SuppressWarnings("deprecation")
public class CalendarModel implements ICalendarModel {

	/* Date Constants */
	private static final String[] months = CalendarUtils.getMonths();
	private static final int _DAYS_IN_WEEK = 7;
	private static final String[] days_short = CalendarUtils.getShortDays();

	/* Event Manager */
	private final CalendarEventManager manager;

	/* The current date */
	private final Date currentDate;

	private final int currentDay;
	private final int currentYear;
	private final int currentMonth;

	private int firstDate;

	/* The displayed Date */
	private int displayedYear;
	private int displayedMonth;

	private int currentFirstDay;

	/* The selected date */
	private Date selectedDate;

	/* Limited Displayed Dates */
	private Date minDate;
	private Date maxDate;

	/* Selected Dates */
	private List<Date> selectedDates;

	private int selectedColumn = 0;
	private int selectedStartWeek;
	private int selectedEndWeek;

	/* Selection Context */
	private SelectionCardinality selectionMode;
	private SelectionType selectionType;
	private int selection;
	private int selectedWeek;

	public CalendarModel() {
		manager = new CalendarEventManager();
		currentDate = new Date();
		currentDay = currentDate.getDate();
		currentYear = currentDate.getYear() + 1900;
		currentMonth = currentDate.getMonth();
		selectedDates = new ArrayList<Date>();
		initModel();
	}

	private void initModel() {
		displayedMonth = currentMonth;
		displayedYear = currentYear;
		selectionMode = SelectionCardinality.SINGLE;
	}

	/* Event Manager */

	public CalendarEventManager getManager() {
		return manager;
	}

	/* First Month Date */

	public int getMonthFirstDate() {
		return firstDate;
	}

	public void setMonthFirstDate(int firstDay) {
		this.firstDate = firstDay;
	}

	/* Display */

	public int getDisplayedYear() {
		return displayedYear;
	}

	public void setDisplayedYear(int displayedYear) {
		this.displayedYear = displayedYear;
	}

	public int getDisplayedMonth() {
		return displayedMonth;
	}

	public void setDisplayedMonth(int displayedMonth) {
		this.displayedMonth = displayedMonth;
	}

	public Date peekDisplayedDate() {
		Date d = new Date();
		d.setYear(displayedYear - 1900);
		d.setMonth(displayedMonth);
		d.setDate(1);
		return d;
	}

	/* Increase / Decrease Methods */

	public void increaseDisplayedYear() {
		this.displayedYear++;
	}

	public void decreaseDisplayedYear() {
		this.displayedYear--;
	}

	public void increaseDisplayedMonth() {
		this.displayedMonth++;
	}

	public void decreaseDisplayedMonth() {
		this.displayedMonth--;
	}

	/* Min & Max displayed dates */

	public void setMinDate(Date min) {
		if (min == null) {
			return;
		}
		this.minDate = (Date) min.clone();
	}

	public void setMaxDate(Date max) {
		if (max == null) {
			return;
		}
		this.maxDate = (Date) max.clone();
	}

	public Date getMinDate() {
		return this.minDate;
	}

	public Date getMaxDate() {
		return this.maxDate;
	}

	/* Selection method */

	public void setSelectionCardinality(SelectionCardinality selectionMode) {
		this.selectionMode = selectionMode;
	}

	public SelectionCardinality getSelectionCardinality() {
		return selectionMode;
	}

	public Date getSelectedDate() {
		return selectedDate;
	}

	public void setSelectedDate(Date selectedDate) {
		if (selectedDate == null) {
			return;
		}
		this.selectedDate = (Date) selectedDate.clone();
	}

	public void setSelectionType(SelectionType selectionType) {
		this.selectionType = selectionType;
	}

	public SelectionType getSelectionType() {
		return selectionType;
	}

	public void setCursorPosition(int selection) {
		this.selection = selection;
	}

	public int getCursorPosition() {
		return selection;
	}

	public Date getCursor() {
		return new Date(this.displayedYear, this.displayedMonth,
				getCursorPosition());
	}

	public void increaseSelection() {
		selection++;
	}

	public void decreaseSelection() {
		selection--;
	}

	public void setSelectedWeek(int selectedWeek) {
		this.selectedWeek = selectedWeek;
	}

	public int getSelectedWeek() {
		return selectedWeek;
	}

	public void increaseSelectedWeek() {
		selectedWeek++;
	}

	public void decreaseSelectedWeek() {
		selectedWeek--;
	}

	public void addSelectedDate(Date d) {
		Iterator<Date> iterator = selectedDates.iterator();

		for (; iterator.hasNext();) {
			Date date = iterator.next();
			int day = date.getDate();
			int month = date.getMonth();
			int year = date.getYear();
			if (day == d.getDate() && month == d.getMonth()
					&& year == d.getYear()) {
				return;
			}
		}
		selectedDates.add(d);
	}

	public void removeDeselectedDate(Date d) {
		Iterator<Date> iterator = selectedDates.iterator();
		for (; iterator.hasNext();) {
			Date date = iterator.next();
			if (d.getYear() == date.getYear()
					&& d.getMonth() == date.getMonth()
					&& d.getDate() == date.getDate()) {
				iterator.remove();
			}
		}
	}

	public void clearSelection() {
		selectedDates.clear();
	}

	public List<Date> getSelectedDates(Date begin, Date end) {
		List<Date> filteredSelectedDates = new ArrayList<Date>();
		for (Date d : selectedDates) {
			if (d.after(begin) && d.before(end)) {
				filteredSelectedDates.add(d);
			}
		}
		return filteredSelectedDates;
	}

	public List<Date> getSelectedDates() {
		return selectedDates;
	}

	public void setSelectedStartWeek(int selectedStartWeek) {
		this.selectedStartWeek = selectedStartWeek;
	}

	public int getSelectedStartWeek() {
		return selectedStartWeek;
	}

	public void setSelectedEndWeek(int selectedEndWeek) {
		this.selectedEndWeek = selectedEndWeek;
	}

	public int getSelectedEndWeek() {
		return selectedEndWeek;
	}

	public void setSelectedColumn(int selectedColumn) {
		this.selectedColumn = selectedColumn;
	}

	public int getSelectedColumn() {
		return selectedColumn;
	}

	/* Current Date */

	public Date getCurrentDate() {
		return currentDate;
	}

	public int getCurrentDay() {
		return currentDay;
	}

	public int getCurrentYear() {
		return currentYear;
	}

	public int getCurrentMonth() {
		return currentMonth;
	}

	public void setCurrentFirstDay(int currentFirstDay) {
		this.currentFirstDay = currentFirstDay;
	}

	public int getCurrentFirstDay() {
		return currentFirstDay;
	}

	/* Constants getters */

	public static int getDaysInWeek() {
		return _DAYS_IN_WEEK;
	}

	public static String[] getDaysShort() {
		return days_short;
	}

	public String getCurrentMonthName() {
		return months[currentMonth];
	}

	public String[] getMonths() {
		return months;
	}
}